import pytest
from unittest.mock import MagicMock, patch
from typing import Dict, Any


# 自定义模拟异常（保持与腾讯云异常结构一致）
class TencentCloudSDKException(Exception):
    def __init__(self, code: str, message: str):
        self.code = code
        self.message = message
        super().__init__(f"[{code}] {message}")


# 模拟所有文档中定义的错误码
MOCK_ERRORS: Dict[str, Dict] = {
    "InvalidFilter": {
        "Error": {"Code": "InvalidFilter", "Message": "无效的过滤器"}
    },
    "InvalidInstanceId.Malformed": {
        "Error": {"Code": "InvalidInstanceId.Malformed", "Message": "实例ID格式错误"}
    },
    "InvalidInstanceType.Malformed": {
        "Error": {"Code": "InvalidInstanceType.Malformed", "Message": "实例类型格式错误"}
    },
    "InvalidParameterValue.InstanceIdMalformed": {
        "Error": {"Code": "InvalidParameterValue.InstanceIdMalformed", "Message": "实例ID参数错误"}
    },
    "InvalidParameterValue.ZoneNotSupported": {
        "Error": {"Code": "InvalidParameterValue.ZoneNotSupported", "Message": "不支持的可用区"}
    },
    "ResourceInsufficient.AvailabilityZoneSoldOut": {
        "Error": {"Code": "ResourceInsufficient.AvailabilityZoneSoldOut", "Message": "可用区已售罄"}
    },
    "UnsupportedOperation": {
        "Error": {"Code": "UnsupportedOperation", "Message": "操作不支持"}
    }
}


# 模拟API客户端
class MockCvmClient:
    def __init__(self):
        self.request = MagicMock()

    def DescribeZoneInstanceConfigInfos(self, Filters: list) -> Dict[str, Any]:
        """模拟接口实现"""
        # 参数校验逻辑
        for filter in Filters:
            if filter['Name'] == 'zone' and 'invalid' in filter['Values'][0]:
                raise TencentCloudSDKException(
                    "InvalidParameterValue.ZoneNotSupported",
                    MOCK_ERRORS["InvalidParameterValue.ZoneNotSupported"]["Error"]["Message"]
                )
            if filter['Name'] == 'instance-charge-type' and filter['Values'][0] not in ['PREPAID', 'POSTPAID_BY_HOUR']:
                raise TencentCloudSDKException(
                    "InvalidParameterValue",
                    "Invalid charge type"
                )

        # 正常响应结构
        return {
            "InstanceTypeQuotaSet": [{
                "InstanceType": "S2.SMALL1",
                "Memory": 1,
                "Cpu": 1,
                "InstanceChargeType": "POSTPAID_BY_HOUR"
            }],
            "RequestId": "mock-request-id"
        }


# 测试类
class TestCvmAPI:
    @pytest.fixture(scope="session", autouse=True)
    def setup_teardown(self):
        """启动和结束函数"""
        print("\n====== 测试开始 ======")
        yield
        print("\n====== 测试结束 ======")

    @pytest.mark.parametrize("error_case", [
        # (测试参数, 预期错误码)
        ([{"Name": "invalid_filter", "Values": ["test"]}], "InvalidFilter"),
        ([{"Name": "zone", "Values": ["invalid-zone"]}], "InvalidParameterValue.ZoneNotSupported"),
        ([{"Name": "instance-charge-type", "Values": ["INVALID"]}], "InvalidParameterValue")
    ])
    def test_error_scenarios(self, error_case):
        """参数化测试错误场景"""
        client = MockCvmClient()
        with patch.object(client, 'DescribeZoneInstanceConfigInfos') as mock_method:
            # 设置模拟方法抛出异常
            mock_method.side_effect = TencentCloudSDKException(
                error_case[1],
                f"Mock {error_case[1]} error"
            )

            with pytest.raises(TencentCloudSDKException) as exc_info:
                client.DescribeZoneInstanceConfigInfos(Filters=error_case[0])

            # 验证错误码匹配
            assert exc_info.value.code == error_case[1]

    def test_success_scenario(self):
        """测试成功场景"""
        client = MockCvmClient()
        valid_filters = [
            {"Name": "zone", "Values": ["ap-guangzhou-2"]},
            {"Name": "instance-charge-type", "Values": ["POSTPAID_BY_HOUR"]}
        ]

        with patch.object(client, 'DescribeZoneInstanceConfigInfos') as mock_method:
            # 设置正常响应
            mock_method.return_value = {
                "InstanceTypeQuotaSet": [{
                    "InstanceType": "S2.SMALL1",
                    "Memory": 1,
                    "Cpu": 1,
                    "InstanceChargeType": "POSTPAID_BY_HOUR"
                }],
                "RequestId": "mock-request-id"
            }

            response = client.DescribeZoneInstanceConfigInfos(Filters=valid_filters)

            # 验证响应结构
            assert isinstance(response, dict)
            assert "RequestId" in response
            assert len(response["InstanceTypeQuotaSet"]) > 0
            assert response["InstanceTypeQuotaSet"][0]["InstanceChargeType"] == "POSTPAID_BY_HOUR"

    @pytest.mark.parametrize("error_code", MOCK_ERRORS.keys())
    def test_all_error_codes(self, error_code: str):
        """覆盖所有文档定义错误码"""
        client = MockCvmClient()

        with patch.object(client, 'DescribeZoneInstanceConfigInfos') as mock_method:
            mock_method.side_effect = TencentCloudSDKException(
                error_code,
                MOCK_ERRORS[error_code]["Error"]["Message"]
            )

            with pytest.raises(TencentCloudSDKException) as exc_info:
                client.DescribeZoneInstanceConfigInfos(Filters=[])

            assert exc_info.value.code == error_code
            assert exc_info.value.message == MOCK_ERRORS[error_code]["Error"]["Message"]


if __name__ == "__main__":
    pytest.main(["-v", "--html=report.html"])